package cn.wsh.basic.service.impl;

import cn.wsh.basic.constant.BaseConstant;
import cn.wsh.basic.dto.RegisterDto;
import cn.wsh.basic.exception.BusinessException;
import cn.wsh.basic.service.IVerifyCodeService;
import cn.wsh.basic.util.StrUtils;
import cn.wsh.basic.util.VerifyCodeUtils;
import cn.wsh.user.domain.Logininfo;
import cn.wsh.user.mapper.LogininfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * 发送验证码业务类
 */
@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LogininfoMapper logininfoMapper;


    /**
     * 公共的发送短信验证码接口
     *
     * @param dto
     */
    @Override
    public void smsCode(RegisterDto dto) {
        String type = dto.getType();
        System.out.println(dto.getType());
        System.out.println(dto);
        if ("register".equals(type)) {
            sendRegisterSmsCode(dto);
        } else if ("binder".equals(type)) {
            sendBinderSmsCode(dto);
        }
    }

    /**
     * 有两种情况会调用到这里：
     * 1.进入页面直接加载一个初始图片
     * 2.看不清楚，刷新验证码
     *
     * @param key
     * @return
     */
    @Override
    public String imageCode(String key) {
        //1.参数空校验
        if (!StringUtils.hasLength(key)) {
            throw new BusinessException("请求key不能为空");
        }

        //2.生成4位随机码  StrUtils
        String code = StrUtils.getComplexRandomString(4);

        //3.随机码保存到redis 以key作为存储redis的key，设置过期时间为5分钟
        redisTemplate.opsForValue().set(
                key,  //key
                code,  //验证码值
                5, //超时时间
                TimeUnit.MINUTES);//超时时间的单位

        //4.将4位随机码化成图片
        //5.将图片使用base64编码成String
        //6.返回String
        return VerifyCodeUtils.VerifyCode(110, 40, code);
    }

    /**
     * 发送绑定相关的短信验证码
     *
     * @param dto
     */
    private void sendBinderSmsCode(RegisterDto dto) {
        //发送短信验证码
        String businessKey = BaseConstant.SmsConstant.BUSINESS_BINDER_PREFIX + dto.getPhone();
        sendSmsCode(businessKey);
    }

    /**
     * 发送注册相关的短信验证码
     *
     * @param dto
     */
    private void sendRegisterSmsCode(RegisterDto dto) {
        //        2.后端接收参数 各种判断一波  校验手机号是否注册了
        if (StringUtils.isEmpty(dto.getPhone())
                || StringUtils.isEmpty(dto.getImageKey())
                || StringUtils.isEmpty(dto.getImageCode())) {
            throw new BusinessException("参数有问题！！");
        }
        String phone = dto.getPhone();
        Logininfo logininfoTmp = logininfoMapper.loadByPhone(phone);
        if (logininfoTmp != null) {
            throw new BusinessException("用户已注册，请直接登录！！！如果忘记密码，请走找回密码流程");
        }

        //3.校验图形验证码  不要区分大小写
        Object imgCodeTmp = redisTemplate.opsForValue().get(dto.getImageKey());
        //。校验是否有效 key（UUID）拿到 codeTmp说明有效
        //。校验是否相等  imgCode=codeTmp
        if (imgCodeTmp == null) {
            throw new BusinessException("图形验证码已经失效，青重新获取");
        }
        if (!imgCodeTmp.toString().equalsIgnoreCase(dto.getImageCode())) {
            throw new BusinessException("请输入正确的图形验证码！！");
        }

        //发送短信验证码
        String businessKey = BaseConstant.SmsConstant.BUSINESS_REGISTER_PREFIX + phone;
        sendSmsCode(businessKey);

    }

    public void sendSmsCode(String businessKey) {
        //4.只有第三步校验相等，才能往下发送短信验证码
        //5.校验短信码是否有效
        //。拼接短信验证码key           register:15982495856
        //。从redis中获取短信验证码      value  9527:3649841265712
        String smsCodeKey = businessKey;//register:15982485856
        Object smsCodeTmp = redisTemplate.opsForValue().get(smsCodeKey);
        String code = "";//短信验证码
        if (smsCodeTmp != null) {  // 9527:3649841265712
            //5.1如果拿到了 说明有效，还没过3分钟失效时间
            Long oldTime = Long.valueOf(smsCodeTmp.toString().split(":")[1]);//3649841265712
            //5.1.1 判断是否过了重发时间（1分钟）
            if (System.currentTimeMillis() - oldTime <= 1 * 60 * 1000) {
                //5.1.1.2如果不过 报错
                throw new BusinessException("请勿重复获取验证码！！！");
            }
            //5.1.1.1如果过了 使用原来的9527，重新存储redis设置过期时间 发短信
            code = smsCodeTmp.toString().split(":")[0]; //使用历史的验证码
        } else {
            //5.2如果拿不到
            //重新生成验证码，存储redis，给他发短信
            code = StrUtils.getComplexRandomString(4);//生成新的验证码
        }

        //6.存储redis并发送短信
        String codeTmp = code + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(
                smsCodeKey,
                codeTmp,
                3,
                TimeUnit.MINUTES
        );
        System.out.println("您好！！，您的验证码是：" + code + "，请在三分钟内使用！！！！");
    }
}
